package com.jhgk.jhcee.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jhgk.jhcee.common.domain.TableListModel;
import com.jhgk.jhcee.common.enums.BasisResultEnum;
import com.jhgk.jhcee.common.exception.ParamException;
import com.jhgk.jhcee.common.resultful.BasisResultful;
import com.jhgk.jhcee.data.auth.entity.*;
import com.jhgk.jhcee.data.auth.mapper.SysMenuInfoMapper;
import com.jhgk.jhcee.data.auth.mapper.SysMenuMetaMapper;
import com.jhgk.jhcee.data.auth.mapper.SysRoleInfoMapper;
import com.jhgk.jhcee.data.auth.mapper.SysRoleMenuRelationMapper;
import com.jhgk.jhcee.system.domain.dao.SysMenuInfoDao;
import com.jhgk.jhcee.system.domain.model.*;
import com.jhgk.jhcee.system.service.SysMenuCacheService;
import com.jhgk.jhcee.system.service.SysMenuInfoService;
import com.jhgk.jhcee.system.service.SysUserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: lemon_xzp
 * @Date: 2021/9/22 11:03
 */
@Service(value = "SysMenuInfoServiceImpl")
public class SysMenuInfoServiceImpl extends ServiceImpl<SysMenuInfoMapper, SysMenuInfo> implements SysMenuInfoService {

    @Resource(name = "SysUserInfoServiceImpl")
    SysUserInfoService sysUserInfoService;

    @Resource(name = "SysMenuCacheServiceImpl")
    SysMenuCacheService sysMenuCacheService;

    @Autowired
    SysRoleInfoMapper sysRoleInfoMapper;

    @Autowired
    SysRoleMenuRelationMapper sysRoleMenuRelationMapper;

    @Autowired
    SysMenuInfoMapper sysMenuInfoMapper;

    @Autowired
    SysMenuMetaMapper sysMenuMetaMapper;

    @Autowired
    SysMenuInfoDao sysMenuInfoDao;

    @Override
    public BasisResultful<Object> getMenuList() {
        BasisResultful<SysUserInfo> user = sysUserInfoService.getCurrentUser();
        if (user.getCode() != BasisResultEnum.SUCCESS.getCode()) {
            return BasisResultful.fail(BasisResultEnum.UNAUTHORIZED);
        }
        List<SysMenuMetaModel> menu = sysMenuCacheService.getMenu(user.getResult().getUserId());
        if (!menu.isEmpty()) {
            return BasisResultful.success(menu);
        }
        List<SysRoleInfo> roleList = sysRoleInfoMapper.getRoleList(user.getResult().getUserId());
        QueryWrapper<SysRoleMenuRelation> wrapper = new QueryWrapper<>();
        List<Long> roleId = roleList.stream().map(SysRoleInfo::getRoleId).collect(Collectors.toList());
        wrapper.select("DISTINCT menu_id").orderByAsc("menu_id");
        wrapper.in("role_id", roleId);
        List<SysRoleMenuRelation> sysRoleMenuRelations = sysRoleMenuRelationMapper.selectList(wrapper);
        // 所有菜单
        List<Long> menuIds = sysRoleMenuRelations.stream().map(SysRoleMenuRelation::getMenuId).collect(Collectors.toList());
        QueryWrapper<SysMenuInfo> menuAll = new QueryWrapper<>();
        menuAll.in("menu_id", menuIds);
        List<SysMenuInfo> rootMenu = sysMenuInfoMapper.selectList(menuAll);
        List<SysMenuMetaModel> rootMenus = new ArrayList<>();
        rootMenu.forEach(rootMe -> {
            SysMenuMetaModel model = new SysMenuMetaModel();
            QueryWrapper<SysMenuMeta> metaWrapper = new QueryWrapper<>();
            metaWrapper.eq("sys_menu_meta_id", rootMe.getSysMenuMetaId());
            SysMenuMeta sysMenuMeta = sysMenuMetaMapper.selectOne(metaWrapper);
            BeanUtil.copyProperties(rootMe, model);
            model.setMeta(sysMenuMeta);
            rootMenus.add(model);
        });
        // 父级菜单
        QueryWrapper<SysMenuInfo> wrapperMenu = new QueryWrapper<>();
        wrapperMenu.isNull("parent_id");
        wrapperMenu.in("menu_id", menuIds);
        List<SysMenuInfo> parentMenu = sysMenuInfoMapper.selectList(wrapperMenu);
        List<SysMenuMetaModel> parentMenuMeta = new ArrayList<>();
        parentMenu.forEach(parentMenus -> {
            QueryWrapper<SysMenuMeta> wrapperMeta = new QueryWrapper<>();
            wrapperMeta.eq("sys_menu_meta_id", parentMenus.getSysMenuMetaId());
            SysMenuMeta sysMenuMeta = sysMenuMetaMapper.selectOne(wrapperMeta);
            SysMenuMetaModel model = new SysMenuMetaModel();
            BeanUtil.copyProperties(parentMenus, model);
            model.setMeta(sysMenuMeta);
            model.setChildren(getChildren(parentMenus.getMenuId(), rootMenus));
            parentMenuMeta.add(model);
        });
        sysMenuCacheService.setMenu(user.getResult().getUserId(), parentMenuMeta);
        return BasisResultful.success(parentMenuMeta);
    }

    @Override
    public BasisResultful<Object> getMenuPage(Integer page, Integer pageSize) {
        return null;
    }

    @Override
    public BasisResultful<Object> getMenuMetaAllList(SysMenuInfoModel model) {
        List<SysMenuMetaRelationModel> menuDetailAll = sysMenuInfoDao.selectDetailAll();
        PageHelper.startPage(model.getPage(), model.getPageSize());
        List<SysMenuMetaRelationModel> menuParentDetail = sysMenuInfoDao.selectDetailParent();
        if (menuParentDetail.isEmpty()) {
            return BasisResultful.success(menuParentDetail);
        }
        menuParentDetail.forEach(menu -> menu.setChildren(getChildrenDetail(menu.getMenuId(), menuDetailAll)));
        PageInfo<SysMenuMetaRelationModel> pageInfo = new PageInfo<>(menuParentDetail);
        return BasisResultful.success(new TableListModel(pageInfo.getList(), pageInfo.getTotal()));
    }

    @Override
    public BasisResultful<Object> addMenu(SysMenuMetaRelationModel model) {
        if (null == model) {
            return BasisResultful.fail(BasisResultEnum.PARAM_IS_NULL);
        }
        if (!this.save(model)) {
            return BasisResultful.fail();
        }
        SysMenuMeta menuMeta = new SysMenuMeta();
        BeanUtil.copyProperties(model, menuMeta);
        int insert = sysMenuMetaMapper.insert(menuMeta);
        return insert > 0 ? BasisResultful.success() : BasisResultful.fail();
    }

    @Override
    public BasisResultful<Object> updateMenu(SysMenuMetaRelationModel model) {
        if (null == model) {
            return BasisResultful.fail(BasisResultEnum.PARAM_IS_NULL);
        }
        QueryWrapper<SysMenuInfo> wrapperMenu = new QueryWrapper<>();
        wrapperMenu.eq("menu_id", model.getMenuId());
        sysMenuInfoMapper.update(model, wrapperMenu);
        // 更新菜单样式
        QueryWrapper<SysMenuMeta> wrapperMeta = new QueryWrapper<>();
        wrapperMeta.eq("sys_menu_meta_id", model.getSysMenuMetaId());
        SysMenuMeta menuMeta = new SysMenuMeta();
        BeanUtil.copyProperties(model, menuMeta);
        sysMenuMetaMapper.update(menuMeta, wrapperMeta);
        // 刷新缓存菜单
        this.renewMenuCache();
        return BasisResultful.success(sysMenuInfoDao.searchDetailMenu(model.getMenuId()));
    }

    @Override
    public BasisResultful<Object> deleteMenu(SysMenuInfoModel model) {
        if (null == model) {
            return BasisResultful.fail(BasisResultEnum.PARAM_IS_NULL);
        }
        QueryWrapper<SysMenuInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("menu_id", model.getMenuId());
        int delete = sysMenuInfoMapper.delete(wrapper);
        // 删除子菜单
        QueryWrapper<SysMenuInfo> childrenWrapper = new QueryWrapper<>();
        childrenWrapper.eq("parent_id", model.getMenuId());
        sysMenuInfoMapper.delete(childrenWrapper);
        // 更新缓存
        if (delete > 0) {
            this.renewMenuCache();
            return BasisResultful.success();
        }
        return BasisResultful.fail();
    }

    @Override
    public BasisResultful<Object> getMenuMetaAll() {
        List<SysMenuMetaRelationModel> menuDetailAll = sysMenuInfoDao.selectDetailAll();
        List<SysMenuMetaRelationModel> menuParentDetail = sysMenuInfoDao.selectDetailParent();
        if (menuParentDetail.isEmpty()) {
            return BasisResultful.success(menuParentDetail);
        }
        menuParentDetail.forEach(menu -> menu.setChildren(getChildrenDetail(menu.getMenuId(), menuDetailAll)));
        return BasisResultful.success(menuParentDetail);
    }

    @Override
    public List<Long> getRoleMenu(Long roleId) {
        if (null == roleId) {
            throw new ParamException("查询角色所属菜单 >>> 传入参数异常");
        }
        QueryWrapper<SysRoleMenuRelation> wrapper = new QueryWrapper<>();
        wrapper.eq("role_id", roleId);
        List<SysRoleMenuRelation> sysRoleMenuRelations = sysRoleMenuRelationMapper.selectList(wrapper);
        return sysRoleMenuRelations.stream().map(SysRoleMenuRelation::getMenuId).collect(Collectors.toList());
    }

    @Override
    public boolean saveRoleMenu(Long roleId, List<Long> menuIds) {
        if (null == roleId || menuIds.isEmpty()) {
            throw new ParamException("更新角色菜单 >>> 传入参数异常");
        }
        // 查询角色关联信息
        QueryWrapper<SysRoleMenuRelation> wrapper = new QueryWrapper<>();
        wrapper.eq("role_id", roleId);
        List<SysRoleMenuRelation> sysRoleMenuRelations = sysRoleMenuRelationMapper.selectList(wrapper);
        if (!sysRoleMenuRelations.isEmpty()) {
            // 删除关联信息
            sysRoleMenuRelationMapper.delete(wrapper);
        }
        // 保存现有关联
        Integer integer = sysRoleMenuRelationMapper.addBatchByRoleId(roleId, menuIds);
        return integer > 0;
    }

    private List<SysMenuMetaModel> getChildren(Long parentId, List<SysMenuMetaModel> rootMenu) {
        // 子菜单
        List<SysMenuMetaModel> childList = new ArrayList<>();
        rootMenu.forEach(menu -> {
            if (null != menu.getParentId()) {
                if (menu.getParentId().equals(parentId)) {
                    childList.add(menu);
                }
            }
        });
        childList.sort(new SysMenuMetaModelComparator());
        childList.forEach(menu -> {
            if (null == menu.getComponent()) {
                menu.setChildren(getChildren(menu.getMenuId(), rootMenu));
            }
        });
        // 推出递归
        if (childList.isEmpty()) return null;
        return childList;
    }

    private List<SysMenuMetaRelationModel> getChildrenDetail(Long parentId, List<SysMenuMetaRelationModel> rootMenu) {
        // 子菜单
        List<SysMenuMetaRelationModel> childList = new ArrayList<>();
        rootMenu.forEach(menu -> {
            if (null != menu.getParentId()) {
                if (menu.getParentId().equals(parentId)) {
                    childList.add(menu);
                }
            }
        });
        childList.sort(new SysMenuMetaRelationModelComparator());
        childList.forEach(menu -> {
            if (null == menu.getComponent()) {
                menu.setChildren(getChildrenDetail(menu.getMenuId(), rootMenu));
            }
        });
        // 推出递归
        if (childList.isEmpty()) return null;
        return childList;
    }

    @Override
    public boolean renewMenuCache() {
        BasisResultful<SysUserInfo> user = sysUserInfoService.getCurrentUser();
        if (user.getCode() != BasisResultEnum.SUCCESS.getCode()) {
            return false;
        }
        if (!sysMenuCacheService.delMenu(user.getResult().getUserId())) {
            return false;
        }
        BasisResultful<Object> menuList = this.getMenuList();
        return menuList.getCode() == BasisResultEnum.SUCCESS.getCode();
    }
}
